package com.apes.scm.account.ledger.model;

import com.apes.framework.jpa.DefaultPersistListener;
import com.apes.framework.jpa.Model;
import com.apes.framework.jpa.comment.Comment;
import com.apes.framework.jpa.generator.ApesGenerator;
import com.apes.framework.plugin.soe.annotations.State;
import com.apes.framework.plugin.soe.annotations.States;
import com.apes.framework.util.ApesConst;
import com.apes.framework.util.LogicalUtil;
import com.apes.scm.account.account.model.AccountingMethod;
import com.apes.scm.account.account.model.InventoryMode;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.party.model.PartyRole;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.SelectBeforeUpdate;

import javax.persistence.*;

/**
 * 功能：往来总账
 *
 * @author xul
 * @create 2018-11-03 10:25
 */
@Getter
@Setter
@SelectBeforeUpdate
@DynamicInsert
@DynamicUpdate
@Entity
@EntityListeners(DefaultPersistListener.class)
@Table(name = Ledger.CONST_TABLE_NAME, indexes = {@Index(name = "u_acc_ledger", columnList = "company_id, partner_id, ledger_account_id, dept_id, inventory_mode, accounting_method", unique = true)})
public class Ledger extends Model {
    public static final String CONST_TABLE_NAME = "acc_ledger";

    @Id
    @Column(name = "id", length = 32)
    @ApesGenerator(code = CONST_TABLE_NAME, name = "往来总账", padding = 10, prefix = "1")
    @Comment("编号")
    private String id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "company_id", referencedColumnName = "id", nullable = false)
    @Comment("公司")
    private PartyRole company;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "dept_id", referencedColumnName = "id", nullable = false)
    @Comment("部门")
    private Dept dept;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "partner_id", referencedColumnName = "id", nullable = false)
    @Comment("合作伙伴")
    private PartyRole partner;

    /**
     * 库存方式
     * 1. 适用于：经销
     * IM_OWN: 自有
     * 2. 适用于：代销、联营
     * IM_CONSIGN: 寄售
     */
    @States(name = "库存方式", values = {
            @State(id = InventoryMode.IM_OWN, name = "自有"),
            @State(id = InventoryMode.IM_CONSIGN, name = "寄售")})
    @Column(name = "inventory_mode", length = 20, nullable = false)
    private String inventoryMode;

    public void setInventoryMode(String inventoryMode) {
        if (LogicalUtil.notIn(inventoryMode, InventoryMode.IM_OWN, InventoryMode.IM_CONSIGN)) {
            throw new RuntimeException("库存方式输入错误！");
        }
        this.inventoryMode = inventoryMode;
    }

    /**
     * 采购核算方式
     * 1. 适用于：经销、代销
     * AM_PURCHASE: 按采购价核算
     * 2. 适用于：联营
     * AM_SALE: 按售价（或码价）核算
     */
    @States(name = "采购核算方式", values = {
            @State(id = AccountingMethod.AM_PURCHASE, name = "按采购价核算"),
            @State(id = AccountingMethod.AM_SALE, name = "按售价（或码价）核算"),
            @State(id = AccountingMethod.AM_REAL, name = "按实时定价核算")
            })
    @Column(name = "accounting_method", length = 20, nullable = false)
    private String accountingMethod;

    public void setAccountingMethod(String accountingMethod) {
        if (LogicalUtil.notIn(accountingMethod, AccountingMethod.AM_PURCHASE, AccountingMethod.AM_SALE, AccountingMethod.AM_REAL)) {
            throw new RuntimeException("核算方式输入错误！");
        }
        this.accountingMethod = accountingMethod;
    }

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "ledger_account_id", referencedColumnName = "id", nullable = false)
    @Comment("帐目类型")
    private LedgerAccount ledgerAccount;

    @Transient
    public String acquireLedgerAccountId() {
        return ledgerAccount == null ? null : ledgerAccount.getId();
    }

    @Column(name = "amount", columnDefinition = ApesConst.FIELD_MONEY_16_4_0, nullable = false)
    @Comment("总账金额")
    private double amount = 0;

    public void setAmount(double incurred) {
        this.amount += incurred;
        if (this.amount >= 0) return;
        if (!ledgerAccount.isMinus()) {
            throw new RuntimeException(String.format("帐目：%s 不允许为负数", ledgerAccount.getName()));
        }
    }

    @Transient
    public LedgerGroup acquireLedgerGroup() {
        return ledgerAccount == null ? null : ledgerAccount.getLedgerGroup();
    }

}
